package com.jorado.redis.extend;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.params.GeoRadiusParam;
import redis.clients.jedis.params.SetParams;
import redis.clients.jedis.params.ZAddParams;
import redis.clients.jedis.params.ZIncrByParams;
import redis.clients.jedis.util.JedisClusterHashTagUtil;
import redis.clients.jedis.util.KeyMergeUtil;
import redis.clients.jedis.util.SafeEncoder;

import java.util.*;

/**
 * 如果节点的状态为fail,则熔断该点
 */
public class JoradolJedisCluster extends JedisCluster {
    //
    protected final JedisClusterConnectionHandler connectionHandler;

    public JoradolJedisCluster(HostAndPort node) {
        this(Collections.singleton(node));
    }

    public JoradolJedisCluster(HostAndPort node, int timeout) {
        this(Collections.singleton(node), timeout);
    }

    public JoradolJedisCluster(HostAndPort node, int timeout, int maxAttempts) {
        this(Collections.singleton(node), timeout, maxAttempts);
    }

    public JoradolJedisCluster(HostAndPort node, final GenericObjectPoolConfig poolConfig) {
        this(Collections.singleton(node), poolConfig);
    }

    public JoradolJedisCluster(HostAndPort node, int timeout, final GenericObjectPoolConfig poolConfig) {
        this(Collections.singleton(node), timeout, poolConfig);
    }

    public JoradolJedisCluster(HostAndPort node, int timeout, int maxAttempts,
                               final GenericObjectPoolConfig poolConfig) {
        this(Collections.singleton(node), timeout, maxAttempts, poolConfig);
    }

    public JoradolJedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
                               int maxAttempts, final GenericObjectPoolConfig poolConfig) {
        this(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, poolConfig);
    }

    public JoradolJedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
                               int maxAttempts, String password, final GenericObjectPoolConfig poolConfig) {
        this(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, password, poolConfig);
    }

    public JoradolJedisCluster(HostAndPort node, int connectionTimeout, int soTimeout,
                               int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig) {
        this(Collections.singleton(node), connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig);
    }

    public JoradolJedisCluster(Set<HostAndPort> nodes) {
        this(nodes, DEFAULT_TIMEOUT);
    }

    public JoradolJedisCluster(Set<HostAndPort> nodes, int timeout) {
        this(nodes, timeout, DEFAULT_MAX_ATTEMPTS);
    }

    public JoradolJedisCluster(Set<HostAndPort> nodes, int timeout, int maxAttempts) {
        this(nodes, timeout, maxAttempts, new GenericObjectPoolConfig());
    }

    public JoradolJedisCluster(Set<HostAndPort> nodes, final GenericObjectPoolConfig poolConfig) {
        this(nodes, DEFAULT_TIMEOUT, DEFAULT_MAX_ATTEMPTS, poolConfig);
    }

    public JoradolJedisCluster(Set<HostAndPort> nodes, int timeout, final GenericObjectPoolConfig poolConfig) {
        this(nodes, timeout, DEFAULT_MAX_ATTEMPTS, poolConfig);
    }

    public JoradolJedisCluster(Set<HostAndPort> jedisClusterNode, int timeout, int maxAttempts,
                               final GenericObjectPoolConfig poolConfig) {
        super(jedisClusterNode, timeout, maxAttempts, poolConfig);
        this.connectionHandler = new JedisClusterConnectionHandlerWraper(jedisClusterNode, poolConfig, timeout);
    }

    public JoradolJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
                               int maxAttempts, final GenericObjectPoolConfig poolConfig) {
        super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, poolConfig);
        this.connectionHandler = new JedisClusterConnectionHandlerWraper(jedisClusterNode, poolConfig, connectionTimeout, soTimeout);
    }

    public JoradolJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
                               int maxAttempts, String password, final GenericObjectPoolConfig poolConfig) {
        super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, poolConfig);
        this.connectionHandler = new JedisClusterConnectionHandlerWraper(jedisClusterNode, poolConfig, connectionTimeout, soTimeout, password);
    }

    public JoradolJedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
                               int maxAttempts, String password, String clientName, final GenericObjectPoolConfig poolConfig) {
        super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, clientName, poolConfig);
        this.connectionHandler = new JedisClusterConnectionHandlerWraper(jedisClusterNode, poolConfig, connectionTimeout, soTimeout, password, clientName);
    }

    public JedisClusterConnectionHandler getConnectionHandler() {
        return this.connectionHandler;
    }

    @Override
    public void close() {
        if (this.connectionHandler != null) {
            this.connectionHandler.close();
        }
        super.close();
    }

    @Override
    public String set(final String key, final String value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.set(key, value);
            }
        }.run(key);
    }

    @Override
    public String set(final String key, final String value, final SetParams params) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.set(key, value, params);
            }
        }.run(key);
    }

    @Override
    public String get(final String key) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.get(key);
            }
        }.run(key);
    }

    @Override
    public Boolean exists(final String key) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.exists(key);
            }
        }.run(key);
    }

    @Override
    public Long exists(final String... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.exists(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public Long persist(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.persist(key);
            }
        }.run(key);
    }

    @Override
    public String type(final String key) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.type(key);
            }
        }.run(key);
    }

    @Override
    public byte[] dump(final String key) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.dump(key);
            }
        }.run(key);
    }

    @Override
    public String restore(final String key, final int ttl, final byte[] serializedValue) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.restore(key, ttl, serializedValue);
            }
        }.run(key);
    }

    @Override
    public Long expire(final String key, final int seconds) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.expire(key, seconds);
            }
        }.run(key);
    }

    @Override
    public Long pexpire(final String key, final long milliseconds) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pexpire(key, milliseconds);
            }
        }.run(key);
    }

    @Override
    public Long expireAt(final String key, final long unixTime) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.expireAt(key, unixTime);
            }
        }.run(key);
    }

    @Override
    public Long pexpireAt(final String key, final long millisecondsTimestamp) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pexpireAt(key, millisecondsTimestamp);
            }
        }.run(key);
    }

    @Override
    public Long ttl(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.ttl(key);
            }
        }.run(key);
    }

    @Override
    public Long pttl(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pttl(key);
            }
        }.run(key);
    }

    @Override
    public Long touch(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.touch(key);
            }
        }.run(key);
    }

    @Override
    public Long touch(final String... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.touch(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public Boolean setbit(final String key, final long offset, final boolean value) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.setbit(key, offset, value);
            }
        }.run(key);
    }

    @Override
    public Boolean setbit(final String key, final long offset, final String value) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.setbit(key, offset, value);
            }
        }.run(key);
    }

    @Override
    public Boolean getbit(final String key, final long offset) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.getbit(key, offset);
            }
        }.run(key);
    }

    @Override
    public Long setrange(final String key, final long offset, final String value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.setrange(key, offset, value);
            }
        }.run(key);
    }

    @Override
    public String getrange(final String key, final long startOffset, final long endOffset) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.getrange(key, startOffset, endOffset);
            }
        }.run(key);
    }

    @Override
    public String getSet(final String key, final String value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.getSet(key, value);
            }
        }.run(key);
    }

    @Override
    public Long setnx(final String key, final String value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.setnx(key, value);
            }
        }.run(key);
    }

    @Override
    public String setex(final String key, final int seconds, final String value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.setex(key, seconds, value);
            }
        }.run(key);
    }

    @Override
    public String psetex(final String key, final long milliseconds, final String value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.psetex(key, milliseconds, value);
            }
        }.run(key);
    }

    @Override
    public Long decrBy(final String key, final long decrement) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.decrBy(key, decrement);
            }
        }.run(key);
    }

    @Override
    public Long decr(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.decr(key);
            }
        }.run(key);
    }

    @Override
    public Long incrBy(final String key, final long increment) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.incrBy(key, increment);
            }
        }.run(key);
    }

    @Override
    public Double incrByFloat(final String key, final double increment) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.incrByFloat(key, increment);
            }
        }.run(key);
    }

    @Override
    public Long incr(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.incr(key);
            }
        }.run(key);
    }

    @Override
    public Long append(final String key, final String value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.append(key, value);
            }
        }.run(key);
    }

    @Override
    public String substr(final String key, final int start, final int end) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.substr(key, start, end);
            }
        }.run(key);
    }

    @Override
    public Long hset(final String key, final String field, final String value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hset(key, field, value);
            }
        }.run(key);
    }

    @Override
    public Long hset(final String key, final Map<String, String> hash) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hset(key, hash);
            }
        }.run(key);
    }

    @Override
    public String hget(final String key, final String field) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.hget(key, field);
            }
        }.run(key);
    }

    @Override
    public Long hsetnx(final String key, final String field, final String value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hsetnx(key, field, value);
            }
        }.run(key);
    }

    @Override
    public String hmset(final String key, final Map<String, String> hash) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.hmset(key, hash);
            }
        }.run(key);
    }

    @Override
    public List<String> hmget(final String key, final String... fields) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.hmget(key, fields);
            }
        }.run(key);
    }

    @Override
    public Long hincrBy(final String key, final String field, final long value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hincrBy(key, field, value);
            }
        }.run(key);
    }

    @Override
    public Boolean hexists(final String key, final String field) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.hexists(key, field);
            }
        }.run(key);
    }

    @Override
    public Long hdel(final String key, final String... field) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hdel(key, field);
            }
        }.run(key);
    }

    @Override
    public Long hlen(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hlen(key);
            }
        }.run(key);
    }

    @Override
    public Set<String> hkeys(final String key) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.hkeys(key);
            }
        }.run(key);
    }

    @Override
    public List<String> hvals(final String key) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.hvals(key);
            }
        }.run(key);
    }

    @Override
    public Map<String, String> hgetAll(final String key) {
        return new JedisClusterCommand<Map<String, String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Map<String, String> execute(Jedis connection) {
                return connection.hgetAll(key);
            }
        }.run(key);
    }

    @Override
    public Long rpush(final String key, final String... string) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.rpush(key, string);
            }
        }.run(key);
    }

    @Override
    public Long lpush(final String key, final String... string) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.lpush(key, string);
            }
        }.run(key);
    }

    @Override
    public Long llen(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.llen(key);
            }
        }.run(key);
    }

    @Override
    public List<String> lrange(final String key, final long start, final long stop) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.lrange(key, start, stop);
            }
        }.run(key);
    }

    @Override
    public String ltrim(final String key, final long start, final long stop) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.ltrim(key, start, stop);
            }
        }.run(key);
    }

    @Override
    public String lindex(final String key, final long index) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.lindex(key, index);
            }
        }.run(key);
    }

    @Override
    public String lset(final String key, final long index, final String value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.lset(key, index, value);
            }
        }.run(key);
    }

    @Override
    public Long lrem(final String key, final long count, final String value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.lrem(key, count, value);
            }
        }.run(key);
    }

    @Override
    public String lpop(final String key) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.lpop(key);
            }
        }.run(key);
    }

    @Override
    public String rpop(final String key) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.rpop(key);
            }
        }.run(key);
    }

    @Override
    public Long sadd(final String key, final String... member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sadd(key, member);
            }
        }.run(key);
    }

    @Override
    public Set<String> smembers(final String key) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.smembers(key);
            }
        }.run(key);
    }

    @Override
    public Long srem(final String key, final String... member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.srem(key, member);
            }
        }.run(key);
    }

    @Override
    public String spop(final String key) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.spop(key);
            }
        }.run(key);
    }

    @Override
    public Set<String> spop(final String key, final long count) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.spop(key, count);
            }
        }.run(key);
    }

    @Override
    public Long scard(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.scard(key);
            }
        }.run(key);
    }

    @Override
    public Boolean sismember(final String key, final String member) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.sismember(key, member);
            }
        }.run(key);
    }

    @Override
    public String srandmember(final String key) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.srandmember(key);
            }
        }.run(key);
    }

    @Override
    public List<String> srandmember(final String key, final int count) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.srandmember(key, count);
            }
        }.run(key);
    }

    @Override
    public Long strlen(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.strlen(key);
            }
        }.run(key);
    }

    @Override
    public Long zadd(final String key, final double score, final String member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, score, member);
            }
        }.run(key);
    }

    @Override
    public Long zadd(final String key, final double score, final String member,
                     final ZAddParams params) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, score, member, params);
            }
        }.run(key);
    }

    @Override
    public Long zadd(final String key, final Map<String, Double> scoreMembers) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, scoreMembers);
            }
        }.run(key);
    }

    @Override
    public Long zadd(final String key, final Map<String, Double> scoreMembers, final ZAddParams params) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, scoreMembers, params);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrange(final String key, final long start, final long stop) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrange(key, start, stop);
            }
        }.run(key);
    }

    @Override
    public Long zrem(final String key, final String... members) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zrem(key, members);
            }
        }.run(key);
    }

    @Override
    public Double zincrby(final String key, final double increment, final String member) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.zincrby(key, increment, member);
            }
        }.run(key);
    }

    @Override
    public Double zincrby(final String key, final double increment, final String member,
                          final ZIncrByParams params) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.zincrby(key, increment, member, params);
            }
        }.run(key);
    }

    @Override
    public Long zrank(final String key, final String member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zrank(key, member);
            }
        }.run(key);
    }

    @Override
    public Long zrevrank(final String key, final String member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zrevrank(key, member);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrevrange(final String key, final long start, final long stop) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrevrange(key, start, stop);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrangeWithScores(final String key, final long start, final long stop) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeWithScores(key, start, stop);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrevrangeWithScores(final String key, final long start, final long stop) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeWithScores(key, start, stop);
            }
        }.run(key);
    }

    @Override
    public Long zcard(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zcard(key);
            }
        }.run(key);
    }

    @Override
    public Double zscore(final String key, final String member) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.zscore(key, member);
            }
        }.run(key);
    }

    @Override
    public List<String> sort(final String key) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.sort(key);
            }
        }.run(key);
    }

    @Override
    public List<String> sort(final String key, final SortingParams sortingParameters) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.sort(key, sortingParameters);
            }
        }.run(key);
    }

    @Override
    public Long zcount(final String key, final double min, final double max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zcount(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Long zcount(final String key, final String min, final String max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zcount(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrangeByScore(final String key, final double min, final double max) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrangeByScore(final String key, final String min, final String max) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrevrangeByScore(final String key, final double max, final double min) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrangeByScore(final String key, final double min, final double max,
                                     final int offset, final int count) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrevrangeByScore(final String key, final String max, final String min) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrangeByScore(final String key, final String min, final String max,
                                     final int offset, final int count) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrevrangeByScore(final String key, final double max, final double min,
                                        final int offset, final int count) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final String key, final double min, final double max) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final String key, final double max, final double min) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final String key, final double min, final double max,
                                              final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrevrangeByScore(final String key, final String max, final String min,
                                        final int offset, final int count) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final String key, final String min, final String max) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final String key, final String max, final String min) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final String key, final String min, final String max,
                                              final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final String key, final double max,
                                                 final double min, final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final String key, final String max,
                                                 final String min, final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min, offset, count);
            }
        }.run(key);
    }

    @Override
    public Long zremrangeByRank(final String key, final long start, final long stop) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByRank(key, start, stop);
            }
        }.run(key);
    }

    @Override
    public Long zremrangeByScore(final String key, final double min, final double max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByScore(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Long zremrangeByScore(final String key, final String min, final String max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByScore(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Long zlexcount(final String key, final String min, final String max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zlexcount(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrangeByLex(final String key, final String min, final String max) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrangeByLex(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrangeByLex(final String key, final String min, final String max,
                                   final int offset, final int count) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrangeByLex(key, min, max, offset, count);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrevrangeByLex(final String key, final String max, final String min) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrevrangeByLex(key, max, min);
            }
        }.run(key);
    }

    @Override
    public Set<String> zrevrangeByLex(final String key, final String max, final String min,
                                      final int offset, final int count) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.zrevrangeByLex(key, max, min, offset, count);
            }
        }.run(key);
    }

    @Override
    public Long zremrangeByLex(final String key, final String min, final String max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByLex(key, min, max);
            }
        }.run(key);
    }

    @Override
    public Long linsert(final String key, final ListPosition where, final String pivot,
                        final String value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.linsert(key, where, pivot, value);
            }
        }.run(key);
    }

    @Override
    public Long lpushx(final String key, final String... string) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.lpushx(key, string);
            }
        }.run(key);
    }

    @Override
    public Long rpushx(final String key, final String... string) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.rpushx(key, string);
            }
        }.run(key);
    }

    @Override
    public Long del(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.del(key);
            }
        }.run(key);
    }

    @Override
    public Long unlink(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.unlink(key);
            }
        }.run(key);
    }

    @Override
    public Long unlink(final String... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.unlink(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public String echo(final String string) {
        // note that it'll be run from arbitary node
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.echo(string);
            }
        }.run(string);
    }

    @Override
    public Long bitcount(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.bitcount(key);
            }
        }.run(key);
    }

    @Override
    public Long bitcount(final String key, final long start, final long end) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.bitcount(key, start, end);
            }
        }.run(key);
    }

    @Override
    public Set<String> keys(final String pattern) {
        if (pattern == null || pattern.isEmpty()) {
            throw new IllegalArgumentException(this.getClass().getSimpleName()
                    + " only supports KEYS commands with non-empty patterns");
        }
        if (!JedisClusterHashTagUtil.isClusterCompliantMatchPattern(pattern)) {
            throw new IllegalArgumentException(this.getClass().getSimpleName()
                    + " only supports KEYS commands with patterns containing hash-tags ( curly-brackets enclosed strings )");
        }
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.keys(pattern);
            }
        }.run(pattern);
    }

    @Override
    public ScanResult<String> scan(final String cursor, final ScanParams params) {

        String matchPattern = null;

        if (params == null || (matchPattern = params.match()) == null || matchPattern.isEmpty()) {
            throw new IllegalArgumentException(JedisCluster.class.getSimpleName()
                    + " only supports SCAN commands with non-empty MATCH patterns");
        }

        if (!JedisClusterHashTagUtil.isClusterCompliantMatchPattern(matchPattern)) {
            throw new IllegalArgumentException(JedisCluster.class.getSimpleName()
                    + " only supports SCAN commands with MATCH patterns containing hash-tags ( curly-brackets enclosed strings )");
        }

        return new JedisClusterCommand<ScanResult<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<String> execute(Jedis connection) {
                return connection.scan(cursor, params);
            }
        }.run(matchPattern);
    }

    @Override
    public ScanResult<Map.Entry<String, String>> hscan(final String key, final String cursor) {
        return new JedisClusterCommand<ScanResult<Map.Entry<String, String>>>(getConnectionHandler(),
                maxAttempts) {
            @Override
            public ScanResult<Map.Entry<String, String>> execute(Jedis connection) {
                return connection.hscan(key, cursor);
            }
        }.run(key);
    }

    @Override
    public ScanResult<String> sscan(final String key, final String cursor) {
        return new JedisClusterCommand<ScanResult<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<String> execute(Jedis connection) {
                return connection.sscan(key, cursor);
            }
        }.run(key);
    }

    @Override
    public ScanResult<Tuple> zscan(final String key, final String cursor) {
        return new JedisClusterCommand<ScanResult<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<Tuple> execute(Jedis connection) {
                return connection.zscan(key, cursor);
            }
        }.run(key);
    }

    @Override
    public Long pfadd(final String key, final String... elements) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pfadd(key, elements);
            }
        }.run(key);
    }

    @Override
    public long pfcount(final String key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pfcount(key);
            }
        }.run(key);
    }

    @Override
    public List<String> blpop(final int timeout, final String key) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.blpop(timeout, key);
            }
        }.run(key);
    }

    @Override
    public List<String> brpop(final int timeout, final String key) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.brpop(timeout, key);
            }
        }.run(key);
    }

    @Override
    public Long del(final String... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.del(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public List<String> blpop(final int timeout, final String... keys) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.blpop(timeout, keys);
            }
        }.run(keys.length, keys);

    }

    @Override
    public List<String> brpop(final int timeout, final String... keys) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.brpop(timeout, keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public List<String> mget(final String... keys) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.mget(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public String mset(final String... keysvalues) {
        String[] keys = new String[keysvalues.length / 2];

        for (int keyIdx = 0; keyIdx < keys.length; keyIdx++) {
            keys[keyIdx] = keysvalues[keyIdx * 2];
        }

        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.mset(keysvalues);
            }
        }.run(keys.length, keys);
    }

    @Override
    public Long msetnx(final String... keysvalues) {
        String[] keys = new String[keysvalues.length / 2];

        for (int keyIdx = 0; keyIdx < keys.length; keyIdx++) {
            keys[keyIdx] = keysvalues[keyIdx * 2];
        }

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.msetnx(keysvalues);
            }
        }.run(keys.length, keys);
    }

    @Override
    public String rename(final String oldkey, final String newkey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.rename(oldkey, newkey);
            }
        }.run(2, oldkey, newkey);
    }

    @Override
    public Long renamenx(final String oldkey, final String newkey) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.renamenx(oldkey, newkey);
            }
        }.run(2, oldkey, newkey);
    }

    @Override
    public String rpoplpush(final String srckey, final String dstkey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.rpoplpush(srckey, dstkey);
            }
        }.run(2, srckey, dstkey);
    }

    @Override
    public Set<String> sdiff(final String... keys) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.sdiff(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public Long sdiffstore(final String dstkey, final String... keys) {
        String[] mergedKeys = KeyMergeUtil.merge(dstkey, keys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sdiffstore(dstkey, keys);
            }
        }.run(mergedKeys.length, mergedKeys);
    }

    @Override
    public Set<String> sinter(final String... keys) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.sinter(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public Long sinterstore(final String dstkey, final String... keys) {
        String[] mergedKeys = KeyMergeUtil.merge(dstkey, keys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sinterstore(dstkey, keys);
            }
        }.run(mergedKeys.length, mergedKeys);
    }

    @Override
    public Long smove(final String srckey, final String dstkey, final String member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.smove(srckey, dstkey, member);
            }
        }.run(2, srckey, dstkey);
    }

    @Override
    public Long sort(final String key, final SortingParams sortingParameters, final String dstkey) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sort(key, sortingParameters, dstkey);
            }
        }.run(2, key, dstkey);
    }

    @Override
    public Long sort(final String key, final String dstkey) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sort(key, dstkey);
            }
        }.run(2, key, dstkey);
    }

    @Override
    public Set<String> sunion(final String... keys) {
        return new JedisClusterCommand<Set<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<String> execute(Jedis connection) {
                return connection.sunion(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public Long sunionstore(final String dstkey, final String... keys) {
        String[] wholeKeys = KeyMergeUtil.merge(dstkey, keys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sunionstore(dstkey, keys);
            }
        }.run(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long zinterstore(final String dstkey, final String... sets) {
        String[] wholeKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zinterstore(dstkey, sets);
            }
        }.run(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long zinterstore(final String dstkey, final ZParams params, final String... sets) {
        String[] mergedKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zinterstore(dstkey, params, sets);
            }
        }.run(mergedKeys.length, mergedKeys);
    }

    @Override
    public Long zunionstore(final String dstkey, final String... sets) {
        String[] mergedKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zunionstore(dstkey, sets);
            }
        }.run(mergedKeys.length, mergedKeys);
    }

    @Override
    public Long zunionstore(final String dstkey, final ZParams params, final String... sets) {
        String[] mergedKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zunionstore(dstkey, params, sets);
            }
        }.run(mergedKeys.length, mergedKeys);
    }

    @Override
    public String brpoplpush(final String source, final String destination, final int timeout) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.brpoplpush(source, destination, timeout);
            }
        }.run(2, source, destination);
    }

    @Override
    public Long publish(final String channel, final String message) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.publish(channel, message);
            }
        }.runWithAnyNode();
    }

    @Override
    public void subscribe(final JedisPubSub jedisPubSub, final String... channels) {
        new JedisClusterCommand<Integer>(getConnectionHandler(), maxAttempts) {
            @Override
            public Integer execute(Jedis connection) {
                connection.subscribe(jedisPubSub, channels);
                return 0;
            }
        }.runWithAnyNode();
    }

    @Override
    public void psubscribe(final JedisPubSub jedisPubSub, final String... patterns) {
        new JedisClusterCommand<Integer>(getConnectionHandler(), maxAttempts) {
            @Override
            public Integer execute(Jedis connection) {
                connection.psubscribe(jedisPubSub, patterns);
                return 0;
            }
        }.runWithAnyNode();
    }

    @Override
    public Long bitop(final BitOP op, final String destKey, final String... srcKeys) {
        String[] mergedKeys = KeyMergeUtil.merge(destKey, srcKeys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.bitop(op, destKey, srcKeys);
            }
        }.run(mergedKeys.length, mergedKeys);
    }

    @Override
    public String pfmerge(final String destkey, final String... sourcekeys) {
        String[] mergedKeys = KeyMergeUtil.merge(destkey, sourcekeys);

        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.pfmerge(destkey, sourcekeys);
            }
        }.run(mergedKeys.length, mergedKeys);
    }

    @Override
    public long pfcount(final String... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pfcount(keys);
            }
        }.run(keys.length, keys);
    }

    @Override
    public Object eval(final String script, final int keyCount, final String... params) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.eval(script, keyCount, params);
            }
        }.run(keyCount, params);
    }

    @Override
    public Object eval(final String script, final String sampleKey) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.eval(script);
            }
        }.run(sampleKey);
    }

    @Override
    public Object eval(final String script, final List<String> keys, final List<String> args) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.eval(script, keys, args);
            }
        }.run(keys.size(), keys.toArray(new String[keys.size()]));
    }

    @Override
    public Object evalsha(final String sha1, final int keyCount, final String... params) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.evalsha(sha1, keyCount, params);
            }
        }.run(keyCount, params);
    }

    @Override
    public Object evalsha(final String sha1, final List<String> keys, final List<String> args) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.evalsha(sha1, keys, args);
            }
        }.run(keys.size(), keys.toArray(new String[keys.size()]));
    }

    @Override
    public Object evalsha(final String sha1, final String sampleKey) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.evalsha(sha1);
            }
        }.run(sampleKey);
    }

    @Override
    public Boolean scriptExists(final String sha1, final String sampleKey) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.scriptExists(sha1);
            }
        }.run(sampleKey);
    }

    @Override
    public List<Boolean> scriptExists(final String sampleKey, final String... sha1) {
        return new JedisClusterCommand<List<Boolean>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<Boolean> execute(Jedis connection) {
                return connection.scriptExists(sha1);
            }
        }.run(sampleKey);
    }

    @Override
    public String scriptLoad(final String script, final String sampleKey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.scriptLoad(script);
            }
        }.run(sampleKey);
    }

    @Override
    public String scriptFlush(final String sampleKey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.scriptFlush();
            }
        }.run(sampleKey);
    }

    @Override
    public String scriptKill(final String sampleKey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.scriptKill();
            }
        }.run(sampleKey);
    }

    @Override
    public Long geoadd(final String key, final double longitude, final double latitude,
                       final String member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.geoadd(key, longitude, latitude, member);
            }
        }.run(key);
    }

    @Override
    public Long geoadd(final String key, final Map<String, GeoCoordinate> memberCoordinateMap) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.geoadd(key, memberCoordinateMap);
            }
        }.run(key);
    }

    @Override
    public Double geodist(final String key, final String member1, final String member2) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.geodist(key, member1, member2);
            }
        }.run(key);
    }

    @Override
    public Double geodist(final String key, final String member1, final String member2,
                          final GeoUnit unit) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.geodist(key, member1, member2, unit);
            }
        }.run(key);
    }

    @Override
    public List<String> geohash(final String key, final String... members) {
        return new JedisClusterCommand<List<String>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<String> execute(Jedis connection) {
                return connection.geohash(key, members);
            }
        }.run(key);
    }

    @Override
    public List<GeoCoordinate> geopos(final String key, final String... members) {
        return new JedisClusterCommand<List<GeoCoordinate>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoCoordinate> execute(Jedis connection) {
                return connection.geopos(key, members);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadius(final String key, final double longitude,
                                             final double latitude, final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadius(key, longitude, latitude, radius, unit);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusReadonly(final String key, final double longitude,
                                                     final double latitude, final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusReadonly(key, longitude, latitude, radius, unit);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadius(final String key, final double longitude,
                                             final double latitude, final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadius(key, longitude, latitude, radius, unit, param);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusReadonly(final String key, final double longitude,
                                                     final double latitude, final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusReadonly(key, longitude, latitude, radius, unit, param);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMember(final String key, final String member,
                                                     final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMember(key, member, radius, unit);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMemberReadonly(final String key, final String member,
                                                             final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMemberReadonly(key, member, radius, unit);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMember(final String key, final String member,
                                                     final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMember(key, member, radius, unit, param);
            }
        }.run(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMemberReadonly(final String key, final String member,
                                                             final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMemberReadonly(key, member, radius, unit, param);
            }
        }.run(key);
    }

    @Override
    public List<Long> bitfield(final String key, final String... arguments) {
        return new JedisClusterCommand<List<Long>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<Long> execute(Jedis connection) {
                return connection.bitfield(key, arguments);
            }
        }.run(key);
    }

    @Override
    public Long hstrlen(final String key, final String field) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hstrlen(key, field);
            }
        }.run(key);
    }

    @Override
    public Long waitReplicas(final String key, final int replicas, final long timeout) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.waitReplicas(replicas, timeout);
            }
        }.run(key);
    }
    ///////

    @Override
    public String set(final byte[] key, final byte[] value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.set(key, value);
            }
        }.runBinary(key);
    }

    @Override
    public String set(final byte[] key, final byte[] value, final SetParams params) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.set(key, value, params);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] get(final byte[] key) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.get(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long exists(final byte[]... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.exists(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public Boolean exists(final byte[] key) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.exists(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long persist(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.persist(key);
            }
        }.runBinary(key);
    }

    @Override
    public String type(final byte[] key) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.type(key);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] dump(final byte[] key) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.dump(key);
            }
        }.runBinary(key);
    }

    @Override
    public String restore(final byte[] key, final int ttl, final byte[] serializedValue) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.restore(key, ttl, serializedValue);
            }
        }.runBinary(key);
    }

    @Override
    public Long expire(final byte[] key, final int seconds) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.expire(key, seconds);
            }
        }.runBinary(key);
    }

    @Override
    public Long pexpire(final byte[] key, final long milliseconds) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pexpire(key, milliseconds);
            }
        }.runBinary(key);
    }

    @Override
    public Long expireAt(final byte[] key, final long unixTime) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.expireAt(key, unixTime);
            }
        }.runBinary(key);
    }

    @Override
    public Long pexpireAt(final byte[] key, final long millisecondsTimestamp) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pexpireAt(key, millisecondsTimestamp);
            }
        }.runBinary(key);
    }

    @Override
    public Long ttl(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.ttl(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long pttl(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pttl(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long touch(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.touch(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long touch(final byte[]... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.touch(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public Boolean setbit(final byte[] key, final long offset, final boolean value) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.setbit(key, offset, value);
            }
        }.runBinary(key);
    }

    @Override
    public Boolean setbit(final byte[] key, final long offset, final byte[] value) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.setbit(key, offset, value);
            }
        }.runBinary(key);
    }

    @Override
    public Boolean getbit(final byte[] key, final long offset) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.getbit(key, offset);
            }
        }.runBinary(key);
    }

    @Override
    public Long setrange(final byte[] key, final long offset, final byte[] value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.setrange(key, offset, value);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] getrange(final byte[] key, final long startOffset, final long endOffset) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.getrange(key, startOffset, endOffset);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] getSet(final byte[] key, final byte[] value) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.getSet(key, value);
            }
        }.runBinary(key);
    }

    @Override
    public Long setnx(final byte[] key, final byte[] value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.setnx(key, value);
            }
        }.runBinary(key);
    }

    @Override
    public String psetex(final byte[] key, final long milliseconds, final byte[] value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.psetex(key, milliseconds, value);
            }
        }.runBinary(key);
    }

    @Override
    public String setex(final byte[] key, final int seconds, final byte[] value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.setex(key, seconds, value);
            }
        }.runBinary(key);
    }

    @Override
    public Long decrBy(final byte[] key, final long decrement) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.decrBy(key, decrement);
            }
        }.runBinary(key);
    }

    @Override
    public Long decr(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.decr(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long incrBy(final byte[] key, final long increment) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.incrBy(key, increment);
            }
        }.runBinary(key);
    }

    @Override
    public Double incrByFloat(final byte[] key, final double increment) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.incrByFloat(key, increment);
            }
        }.runBinary(key);
    }

    @Override
    public Long incr(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.incr(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long append(final byte[] key, final byte[] value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.append(key, value);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] substr(final byte[] key, final int start, final int end) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.substr(key, start, end);
            }
        }.runBinary(key);
    }

    @Override
    public Long hset(final byte[] key, final byte[] field, final byte[] value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hset(key, field, value);
            }
        }.runBinary(key);
    }

    @Override
    public Long hset(final byte[] key, final Map<byte[], byte[]> hash) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hset(key, hash);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] hget(final byte[] key, final byte[] field) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.hget(key, field);
            }
        }.runBinary(key);
    }

    @Override
    public Long hsetnx(final byte[] key, final byte[] field, final byte[] value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hsetnx(key, field, value);
            }
        }.runBinary(key);
    }

    @Override
    public String hmset(final byte[] key, final Map<byte[], byte[]> hash) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.hmset(key, hash);
            }
        }.runBinary(key);
    }

    @Override
    public List<byte[]> hmget(final byte[] key, final byte[]... fields) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.hmget(key, fields);
            }
        }.runBinary(key);
    }

    @Override
    public Long hincrBy(final byte[] key, final byte[] field, final long value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hincrBy(key, field, value);
            }
        }.runBinary(key);
    }

    @Override
    public Double hincrByFloat(final byte[] key, final byte[] field, final double value) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.hincrByFloat(key, field, value);
            }
        }.runBinary(key);
    }

    @Override
    public Boolean hexists(final byte[] key, final byte[] field) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.hexists(key, field);
            }
        }.runBinary(key);
    }

    @Override
    public Long hdel(final byte[] key, final byte[]... field) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hdel(key, field);
            }
        }.runBinary(key);
    }

    @Override
    public Long hlen(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hlen(key);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> hkeys(final byte[] key) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.hkeys(key);
            }
        }.runBinary(key);
    }

    @Override
    public Collection<byte[]> hvals(final byte[] key) {
        return new JedisClusterCommand<Collection<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Collection<byte[]> execute(Jedis connection) {
                return connection.hvals(key);
            }
        }.runBinary(key);
    }

    @Override
    public Map<byte[], byte[]> hgetAll(final byte[] key) {
        return new JedisClusterCommand<Map<byte[], byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Map<byte[], byte[]> execute(Jedis connection) {
                return connection.hgetAll(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long rpush(final byte[] key, final byte[]... args) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.rpush(key, args);
            }
        }.runBinary(key);
    }

    @Override
    public Long lpush(final byte[] key, final byte[]... args) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.lpush(key, args);
            }
        }.runBinary(key);
    }

    @Override
    public Long llen(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.llen(key);
            }
        }.runBinary(key);
    }

    @Override
    public List<byte[]> lrange(final byte[] key, final long start, final long stop) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.lrange(key, start, stop);
            }
        }.runBinary(key);
    }

    @Override
    public String ltrim(final byte[] key, final long start, final long stop) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.ltrim(key, start, stop);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] lindex(final byte[] key, final long index) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.lindex(key, index);
            }
        }.runBinary(key);
    }

    @Override
    public String lset(final byte[] key, final long index, final byte[] value) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.lset(key, index, value);
            }
        }.runBinary(key);
    }

    @Override
    public Long lrem(final byte[] key, final long count, final byte[] value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.lrem(key, count, value);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] lpop(final byte[] key) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.lpop(key);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] rpop(final byte[] key) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.rpop(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long sadd(final byte[] key, final byte[]... member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sadd(key, member);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> smembers(final byte[] key) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.smembers(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long srem(final byte[] key, final byte[]... member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.srem(key, member);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] spop(final byte[] key) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.spop(key);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> spop(final byte[] key, final long count) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.spop(key, count);
            }
        }.runBinary(key);
    }

    @Override
    public Long scard(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.scard(key);
            }
        }.runBinary(key);
    }

    @Override
    public Boolean sismember(final byte[] key, final byte[] member) {
        return new JedisClusterCommand<Boolean>(getConnectionHandler(), maxAttempts) {
            @Override
            public Boolean execute(Jedis connection) {
                return connection.sismember(key, member);
            }
        }.runBinary(key);
    }

    @Override
    public byte[] srandmember(final byte[] key) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.srandmember(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long strlen(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.strlen(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long zadd(final byte[] key, final double score, final byte[] member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, score, member);
            }
        }.runBinary(key);
    }

    @Override
    public Long zadd(final byte[] key, final double score, final byte[] member,
                     final ZAddParams params) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, score, member, params);
            }
        }.runBinary(key);
    }

    @Override
    public Long zadd(final byte[] key, final Map<byte[], Double> scoreMembers) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, scoreMembers);
            }
        }.runBinary(key);
    }

    @Override
    public Long zadd(final byte[] key, final Map<byte[], Double> scoreMembers, final ZAddParams params) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zadd(key, scoreMembers, params);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrange(final byte[] key, final long start, final long stop) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrange(key, start, stop);
            }
        }.runBinary(key);
    }

    @Override
    public Long zrem(final byte[] key, final byte[]... members) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zrem(key, members);
            }
        }.runBinary(key);
    }

    @Override
    public Double zincrby(final byte[] key, final double increment, final byte[] member) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.zincrby(key, increment, member);
            }
        }.runBinary(key);
    }

    @Override
    public Double zincrby(final byte[] key, final double increment, final byte[] member,
                          final ZIncrByParams params) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.zincrby(key, increment, member, params);
            }
        }.runBinary(key);
    }

    @Override
    public Long zrank(final byte[] key, final byte[] member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zrank(key, member);
            }
        }.runBinary(key);
    }

    @Override
    public Long zrevrank(final byte[] key, final byte[] member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zrevrank(key, member);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrevrange(final byte[] key, final long start, final long stop) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrevrange(key, start, stop);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrangeWithScores(final byte[] key, final long start, final long stop) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeWithScores(key, start, stop);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrevrangeWithScores(final byte[] key, final long start, final long stop) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeWithScores(key, start, stop);
            }
        }.runBinary(key);
    }

    @Override
    public Long zcard(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zcard(key);
            }
        }.runBinary(key);
    }

    @Override
    public Double zscore(final byte[] key, final byte[] member) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.zscore(key, member);
            }
        }.runBinary(key);
    }

    @Override
    public List<byte[]> sort(final byte[] key) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.sort(key);
            }
        }.runBinary(key);
    }

    @Override
    public List<byte[]> sort(final byte[] key, final SortingParams sortingParameters) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.sort(key, sortingParameters);
            }
        }.runBinary(key);
    }

    @Override
    public Long zcount(final byte[] key, final double min, final double max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zcount(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Long zcount(final byte[] key, final byte[] min, final byte[] max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zcount(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrangeByScore(final byte[] key, final double min, final double max) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrangeByScore(final byte[] key, final byte[] min, final byte[] max) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrevrangeByScore(final byte[] key, final double max, final double min) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrangeByScore(final byte[] key, final double min, final double max,
                                     final int offset, final int count) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrevrangeByScore(final byte[] key, final byte[] max, final byte[] min) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrangeByScore(final byte[] key, final byte[] min, final byte[] max,
                                     final int offset, final int count) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrangeByScore(key, min, max, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrevrangeByScore(final byte[] key, final double max, final double min,
                                        final int offset, final int count) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final byte[] key, final double min, final double max) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final byte[] key, final double max, final double min) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final byte[] key, final double min, final double max,
                                              final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrevrangeByScore(final byte[] key, final byte[] max, final byte[] min,
                                        final int offset, final int count) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrevrangeByScore(key, max, min, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final byte[] key, final byte[] min, final byte[] max) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final byte[] key, final byte[] max, final byte[] min) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrangeByScoreWithScores(final byte[] key, final byte[] min, final byte[] max,
                                              final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrangeByScoreWithScores(key, min, max, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final byte[] key, final double max,
                                                 final double min, final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<Tuple> zrevrangeByScoreWithScores(final byte[] key, final byte[] max,
                                                 final byte[] min, final int offset, final int count) {
        return new JedisClusterCommand<Set<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<Tuple> execute(Jedis connection) {
                return connection.zrevrangeByScoreWithScores(key, max, min, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Long zremrangeByRank(final byte[] key, final long start, final long stop) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByRank(key, start, stop);
            }
        }.runBinary(key);
    }

    @Override
    public Long zremrangeByScore(final byte[] key, final double min, final double max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByScore(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Long zremrangeByScore(final byte[] key, final byte[] min, final byte[] max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByScore(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Long linsert(final byte[] key, final ListPosition where, final byte[] pivot,
                        final byte[] value) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.linsert(key, where, pivot, value);
            }
        }.runBinary(key);
    }

    @Override
    public Long lpushx(final byte[] key, final byte[]... arg) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.lpushx(key, arg);
            }
        }.runBinary(key);
    }

    @Override
    public Long rpushx(final byte[] key, final byte[]... arg) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.rpushx(key, arg);
            }
        }.runBinary(key);
    }

    @Override
    public Long del(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.del(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long unlink(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.unlink(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long unlink(final byte[]... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.unlink(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public byte[] echo(final byte[] arg) {
        // note that it'll be run from arbitary node
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.echo(arg);
            }
        }.runBinary(arg);
    }

    @Override
    public Long bitcount(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.bitcount(key);
            }
        }.runBinary(key);
    }

    @Override
    public Long bitcount(final byte[] key, final long start, final long end) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.bitcount(key, start, end);
            }
        }.runBinary(key);
    }

    @Override
    public Long pfadd(final byte[] key, final byte[]... elements) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pfadd(key, elements);
            }
        }.runBinary(key);
    }

    @Override
    public long pfcount(final byte[] key) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pfcount(key);
            }
        }.runBinary(key);
    }

    @Override
    public List<byte[]> srandmember(final byte[] key, final int count) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.srandmember(key, count);
            }
        }.runBinary(key);
    }

    @Override
    public Long zlexcount(final byte[] key, final byte[] min, final byte[] max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zlexcount(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrangeByLex(final byte[] key, final byte[] min, final byte[] max) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrangeByLex(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrangeByLex(final byte[] key, final byte[] min, final byte[] max,
                                   final int offset, final int count) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrangeByLex(key, min, max, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrevrangeByLex(final byte[] key, final byte[] max, final byte[] min) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrevrangeByLex(key, max, min);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> zrevrangeByLex(final byte[] key, final byte[] max, final byte[] min,
                                      final int offset, final int count) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.zrevrangeByLex(key, max, min, offset, count);
            }
        }.runBinary(key);
    }

    @Override
    public Long zremrangeByLex(final byte[] key, final byte[] min, final byte[] max) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zremrangeByLex(key, min, max);
            }
        }.runBinary(key);
    }

    @Override
    public Object eval(final byte[] script, final byte[] keyCount, final byte[]... params) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.eval(script, keyCount, params);
            }
        }.runBinary(Integer.parseInt(SafeEncoder.encode(keyCount)), params);
    }

    @Override
    public Object eval(final byte[] script, final int keyCount, final byte[]... params) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.eval(script, keyCount, params);
            }
        }.runBinary(keyCount, params);
    }

    @Override
    public Object eval(final byte[] script, final List<byte[]> keys, final List<byte[]> args) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.eval(script, keys, args);
            }
        }.runBinary(keys.size(), keys.toArray(new byte[keys.size()][]));
    }

    @Override
    public Object eval(final byte[] script, final byte[] sampleKey) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.eval(script);
            }
        }.runBinary(sampleKey);
    }

    @Override
    public Object evalsha(final byte[] sha1, final byte[] sampleKey) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.evalsha(sha1);
            }
        }.runBinary(sampleKey);
    }

    @Override
    public Object evalsha(final byte[] sha1, final List<byte[]> keys, final List<byte[]> args) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.evalsha(sha1, keys, args);
            }
        }.runBinary(keys.size(), keys.toArray(new byte[keys.size()][]));
    }

    @Override
    public Object evalsha(final byte[] sha1, final int keyCount, final byte[]... params) {
        return new JedisClusterCommand<Object>(getConnectionHandler(), maxAttempts) {
            @Override
            public Object execute(Jedis connection) {
                return connection.evalsha(sha1, keyCount, params);
            }
        }.runBinary(keyCount, params);
    }

    @Override
    public List<Long> scriptExists(final byte[] sampleKey, final byte[]... sha1) {
        return new JedisClusterCommand<List<Long>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<Long> execute(Jedis connection) {
                return connection.scriptExists(sha1);
            }
        }.runBinary(sampleKey);
    }

    @Override
    public byte[] scriptLoad(final byte[] script, final byte[] sampleKey) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.scriptLoad(script);
            }
        }.runBinary(sampleKey);
    }

    @Override
    public String scriptFlush(final byte[] sampleKey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.scriptFlush();
            }
        }.runBinary(sampleKey);
    }

    @Override
    public String scriptKill(final byte[] sampleKey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.scriptKill();
            }
        }.runBinary(sampleKey);
    }

    @Override
    public Long del(final byte[]... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.del(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public List<byte[]> blpop(final int timeout, final byte[]... keys) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.blpop(timeout, keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public List<byte[]> brpop(final int timeout, final byte[]... keys) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.brpop(timeout, keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public List<byte[]> mget(final byte[]... keys) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.mget(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public String mset(final byte[]... keysvalues) {
        byte[][] keys = new byte[keysvalues.length / 2][];

        for (int keyIdx = 0; keyIdx < keys.length; keyIdx++) {
            keys[keyIdx] = keysvalues[keyIdx * 2];
        }

        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.mset(keysvalues);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public Long msetnx(final byte[]... keysvalues) {
        byte[][] keys = new byte[keysvalues.length / 2][];

        for (int keyIdx = 0; keyIdx < keys.length; keyIdx++) {
            keys[keyIdx] = keysvalues[keyIdx * 2];
        }

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.msetnx(keysvalues);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public String rename(final byte[] oldkey, final byte[] newkey) {
        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.rename(oldkey, newkey);
            }
        }.runBinary(2, oldkey, newkey);
    }

    @Override
    public Long renamenx(final byte[] oldkey, final byte[] newkey) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.renamenx(oldkey, newkey);
            }
        }.runBinary(2, oldkey, newkey);
    }

    @Override
    public byte[] rpoplpush(final byte[] srckey, final byte[] dstkey) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.rpoplpush(srckey, dstkey);
            }
        }.runBinary(2, srckey, dstkey);
    }

    @Override
    public Set<byte[]> sdiff(final byte[]... keys) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.sdiff(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public Long sdiffstore(final byte[] dstkey, final byte[]... keys) {
        byte[][] wholeKeys = KeyMergeUtil.merge(dstkey, keys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sdiffstore(dstkey, keys);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public Set<byte[]> sinter(final byte[]... keys) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.sinter(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public Long sinterstore(final byte[] dstkey, final byte[]... keys) {
        byte[][] wholeKeys = KeyMergeUtil.merge(dstkey, keys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sinterstore(dstkey, keys);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long smove(final byte[] srckey, final byte[] dstkey, final byte[] member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.smove(srckey, dstkey, member);
            }
        }.runBinary(2, srckey, dstkey);
    }

    @Override
    public Long sort(final byte[] key, final SortingParams sortingParameters, final byte[] dstkey) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sort(key, sortingParameters, dstkey);
            }
        }.runBinary(2, key, dstkey);
    }

    @Override
    public Long sort(final byte[] key, final byte[] dstkey) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sort(key, dstkey);
            }
        }.runBinary(2, key, dstkey);
    }

    @Override
    public Set<byte[]> sunion(final byte[]... keys) {
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.sunion(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public Long sunionstore(final byte[] dstkey, final byte[]... keys) {
        byte[][] wholeKeys = KeyMergeUtil.merge(dstkey, keys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.sunionstore(dstkey, keys);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long zinterstore(final byte[] dstkey, final byte[]... sets) {
        byte[][] wholeKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zinterstore(dstkey, sets);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long zinterstore(final byte[] dstkey, final ZParams params, final byte[]... sets) {
        byte[][] wholeKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zinterstore(dstkey, params, sets);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long zunionstore(final byte[] dstkey, final byte[]... sets) {
        byte[][] wholeKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zunionstore(dstkey, sets);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long zunionstore(final byte[] dstkey, final ZParams params, final byte[]... sets) {
        byte[][] wholeKeys = KeyMergeUtil.merge(dstkey, sets);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.zunionstore(dstkey, params, sets);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public byte[] brpoplpush(final byte[] source, final byte[] destination, final int timeout) {
        return new JedisClusterCommand<byte[]>(getConnectionHandler(), maxAttempts) {
            @Override
            public byte[] execute(Jedis connection) {
                return connection.brpoplpush(source, destination, timeout);
            }
        }.runBinary(2, source, destination);
    }

    @Override
    public Long publish(final byte[] channel, final byte[] message) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.publish(channel, message);
            }
        }.runWithAnyNode();
    }

    @Override
    public void subscribe(final BinaryJedisPubSub jedisPubSub, final byte[]... channels) {
        new JedisClusterCommand<Integer>(getConnectionHandler(), maxAttempts) {
            @Override
            public Integer execute(Jedis connection) {
                connection.subscribe(jedisPubSub, channels);
                return 0;
            }
        }.runWithAnyNode();
    }

    @Override
    public void psubscribe(final BinaryJedisPubSub jedisPubSub, final byte[]... patterns) {
        new JedisClusterCommand<Integer>(getConnectionHandler(), maxAttempts) {
            @Override
            public Integer execute(Jedis connection) {
                connection.psubscribe(jedisPubSub, patterns);
                return 0;
            }
        }.runWithAnyNode();
    }

    @Override
    public Long bitop(final BitOP op, final byte[] destKey, final byte[]... srcKeys) {
        byte[][] wholeKeys = KeyMergeUtil.merge(destKey, srcKeys);

        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.bitop(op, destKey, srcKeys);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public String pfmerge(final byte[] destkey, final byte[]... sourcekeys) {
        byte[][] wholeKeys = KeyMergeUtil.merge(destkey, sourcekeys);

        return new JedisClusterCommand<String>(getConnectionHandler(), maxAttempts) {
            @Override
            public String execute(Jedis connection) {
                return connection.pfmerge(destkey, sourcekeys);
            }
        }.runBinary(wholeKeys.length, wholeKeys);
    }

    @Override
    public Long pfcount(final byte[]... keys) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.pfcount(keys);
            }
        }.runBinary(keys.length, keys);
    }

    @Override
    public Long geoadd(final byte[] key, final double longitude, final double latitude,
                       final byte[] member) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.geoadd(key, longitude, latitude, member);
            }
        }.runBinary(key);
    }

    @Override
    public Long geoadd(final byte[] key, final Map<byte[], GeoCoordinate> memberCoordinateMap) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.geoadd(key, memberCoordinateMap);
            }
        }.runBinary(key);
    }

    @Override
    public Double geodist(final byte[] key, final byte[] member1, final byte[] member2) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.geodist(key, member1, member2);
            }
        }.runBinary(key);
    }

    @Override
    public Double geodist(final byte[] key, final byte[] member1, final byte[] member2,
                          final GeoUnit unit) {
        return new JedisClusterCommand<Double>(getConnectionHandler(), maxAttempts) {
            @Override
            public Double execute(Jedis connection) {
                return connection.geodist(key, member1, member2, unit);
            }
        }.runBinary(key);
    }

    @Override
    public List<byte[]> geohash(final byte[] key, final byte[]... members) {
        return new JedisClusterCommand<List<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<byte[]> execute(Jedis connection) {
                return connection.geohash(key, members);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoCoordinate> geopos(final byte[] key, final byte[]... members) {
        return new JedisClusterCommand<List<GeoCoordinate>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoCoordinate> execute(Jedis connection) {
                return connection.geopos(key, members);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadius(final byte[] key, final double longitude,
                                             final double latitude, final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadius(key, longitude, latitude, radius, unit);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusReadonly(final byte[] key, final double longitude,
                                                     final double latitude, final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusReadonly(key, longitude, latitude, radius, unit);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadius(final byte[] key, final double longitude,
                                             final double latitude, final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadius(key, longitude, latitude, radius, unit, param);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusReadonly(final byte[] key, final double longitude,
                                                     final double latitude, final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusReadonly(key, longitude, latitude, radius, unit, param);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMember(final byte[] key, final byte[] member,
                                                     final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMember(key, member, radius, unit);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMemberReadonly(final byte[] key, final byte[] member,
                                                             final double radius, final GeoUnit unit) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMemberReadonly(key, member, radius, unit);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMember(final byte[] key, final byte[] member,
                                                     final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMember(key, member, radius, unit, param);
            }
        }.runBinary(key);
    }

    @Override
    public List<GeoRadiusResponse> georadiusByMemberReadonly(final byte[] key, final byte[] member,
                                                             final double radius, final GeoUnit unit, final GeoRadiusParam param) {
        return new JedisClusterCommand<List<GeoRadiusResponse>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<GeoRadiusResponse> execute(Jedis connection) {
                return connection.georadiusByMemberReadonly(key, member, radius, unit, param);
            }
        }.runBinary(key);
    }

    @Override
    public Set<byte[]> keys(final byte[] pattern) {
        if (pattern == null || pattern.length == 0) {
            throw new IllegalArgumentException(this.getClass().getSimpleName()
                    + " only supports KEYS commands with non-empty patterns");
        }
        if (!JedisClusterHashTagUtil.isClusterCompliantMatchPattern(pattern)) {
            throw new IllegalArgumentException(this.getClass().getSimpleName()
                    + " only supports KEYS commands with patterns containing hash-tags ( curly-brackets enclosed strings )");
        }
        return new JedisClusterCommand<Set<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public Set<byte[]> execute(Jedis connection) {
                return connection.keys(pattern);
            }
        }.runBinary(pattern);
    }

    @Override
    public ScanResult<byte[]> scan(final byte[] cursor, final ScanParams params) {

        byte[] matchPattern = null;

        if (params == null || (matchPattern = params.binaryMatch()) == null || matchPattern.length == 0) {
            throw new IllegalArgumentException(BinaryJedisCluster.class.getSimpleName()
                    + " only supports SCAN commands with non-empty MATCH patterns");
        }

        if (!JedisClusterHashTagUtil.isClusterCompliantMatchPattern(matchPattern)) {
            throw new IllegalArgumentException(BinaryJedisCluster.class.getSimpleName()
                    + " only supports SCAN commands with MATCH patterns containing hash-tags ( curly-brackets enclosed strings )");
        }

        return new JedisClusterCommand<ScanResult<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<byte[]> execute(Jedis connection) {
                return connection.scan(cursor, params);
            }
        }.runBinary(matchPattern);
    }

    @Override
    public ScanResult<Map.Entry<byte[], byte[]>> hscan(final byte[] key, final byte[] cursor) {
        return new JedisClusterCommand<ScanResult<Map.Entry<byte[], byte[]>>>(getConnectionHandler(),
                maxAttempts) {
            @Override
            public ScanResult<Map.Entry<byte[], byte[]>> execute(Jedis connection) {
                return connection.hscan(key, cursor);
            }
        }.runBinary(key);
    }

    @Override
    public ScanResult<Map.Entry<byte[], byte[]>> hscan(final byte[] key, final byte[] cursor,
                                                       final ScanParams params) {
        return new JedisClusterCommand<ScanResult<Map.Entry<byte[], byte[]>>>(getConnectionHandler(),
                maxAttempts) {
            @Override
            public ScanResult<Map.Entry<byte[], byte[]>> execute(Jedis connection) {
                return connection.hscan(key, cursor, params);
            }
        }.runBinary(key);
    }

    @Override
    public ScanResult<byte[]> sscan(final byte[] key, final byte[] cursor) {
        return new JedisClusterCommand<ScanResult<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<byte[]> execute(Jedis connection) {
                return connection.sscan(key, cursor);
            }
        }.runBinary(key);
    }

    @Override
    public ScanResult<byte[]> sscan(final byte[] key, final byte[] cursor, final ScanParams params) {
        return new JedisClusterCommand<ScanResult<byte[]>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<byte[]> execute(Jedis connection) {
                return connection.sscan(key, cursor, params);
            }
        }.runBinary(key);
    }

    @Override
    public ScanResult<Tuple> zscan(final byte[] key, final byte[] cursor) {
        return new JedisClusterCommand<ScanResult<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<Tuple> execute(Jedis connection) {
                return connection.zscan(key, cursor);
            }
        }.runBinary(key);
    }

    @Override
    public ScanResult<Tuple> zscan(final byte[] key, final byte[] cursor, final ScanParams params) {
        return new JedisClusterCommand<ScanResult<Tuple>>(getConnectionHandler(), maxAttempts) {
            @Override
            public ScanResult<Tuple> execute(Jedis connection) {
                return connection.zscan(key, cursor, params);
            }
        }.runBinary(key);
    }

    @Override
    public List<Long> bitfield(final byte[] key, final byte[]... arguments) {
        return new JedisClusterCommand<List<Long>>(getConnectionHandler(), maxAttempts) {
            @Override
            public List<Long> execute(Jedis connection) {
                return connection.bitfield(key, arguments);
            }
        }.runBinary(key);
    }

    @Override
    public Long hstrlen(final byte[] key, final byte[] field) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.hstrlen(key, field);
            }
        }.runBinary(key);
    }

    @Override
    public Long waitReplicas(final byte[] key, final int replicas, final long timeout) {
        return new JedisClusterCommand<Long>(getConnectionHandler(), maxAttempts) {
            @Override
            public Long execute(Jedis connection) {
                return connection.waitReplicas(replicas, timeout);
            }
        }.runBinary(key);
    }

}
